package demo.designPattern.proxy;

import demo.spring.service.IUserDAO;
import demo.spring.service.impl.UserDAO;
import org.junit.Test;

import java.time.LocalTime;

/**
 * 静态代理是一种设计模式，它通过引入一个代理类来控制对目标对象的访问。
 * 代理类与目标类实现相同的接口，代理对象在运行时直接通过这个接口与目标对象进行交互。
 * 这样做的好处是可以在不修改目标类的情况下，添加一些额外的功能，例如日志记录、权限控制、事务处理等。
 * <p>
 * 1. 静态代理的实现步骤
 * <li>定义接口：创建一个接口，定义目标对象和代理对象都需要实现的方法。
 * <li>实现目标类：创建一个实现接口的类，定义核心业务逻辑。
 * <li>实现代理类：创建一个代理类，也实现该接口，通过代理类对目标类的方法进行调用，并在调用前后增加额外的逻辑。
 * <p>
 * 静态代理的优缺点
 * <p>
 * 优点：
 * <li>解耦：通过代理层可以将业务逻辑与横切关注点（如日志、事务等）分离，提高代码的可维护性。
 * <li>透明性：客户端代码只需和接口交互，无需关心真实对象的实现细节。
 * <li>增强功能：可以在不改变目标对象代码的情况下，增强目标对象的功能。
 * <p>
 * 缺点：
 * <li>类数量增加：每个目标类都需要一个代理类，可能导致类的数量增加，从而使得系统结构变得复杂。
 * <li>灵活性较低：静态代理在编译时就确定了目标对象，无法在运行时动态替换目标对象。
 */
public class StaticProxyDemo {

    /**
     * 静态代理：由程序员创建或特定工具自动生成源代码，再对其编译。在程序运行前，代理类的.class文件就已经存在了
     */
    @Test
    public void testStaticProxy() {
        // 实现目标类
        IUserDAO userDAO = new UserDAO();
        // 实现代理类
        IUserDAO staticProxy = new UserDaoStaticProxy(userDAO);
        // 通过代理类调用目标方法
        staticProxy.findUserById("张无忌");
    }
}

/**
 * 静态代理
 */
class UserDaoStaticProxy implements IUserDAO {

    public IUserDAO userDao;

    public UserDaoStaticProxy(IUserDAO userDao) {
        this.userDao = userDao;
    }

    @Override
    public Boolean findUserById(String userId) {
        beforeInvoke();
        boolean result = userDao.findUserById(userId);
        afterInvoke();
        return result;
    }

    // 记录方法调用时间
    public void beforeInvoke() {
        System.out.println("调用时间：" + LocalTime.now());
    }

    public void afterInvoke() {
        System.out.println("结束时间：" + LocalTime.now());
    }
}
